package co.edu.usbcali.raju.games.chess.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;

import co.edu.usbcali.raju.games.chess.controller.ChessController;
import co.edu.usbcali.raju.model.Board;
import co.edu.usbcali.raju.model.Cell;
import co.edu.usbcali.raju.model.IEvaluator;

public class ChessBoard implements Board{
	public static final int SIDE=8;
	public static final String TURN="turn";
	public static final String WHITE="white";
	public static final String BLACK="black";
	public static final String SHORT_CASTLING="sc";
	public static final String LONG_CASTLING="lc";
	public static final String ET_PASSANT="ep";
	public static final String HALFMOVE_CLOCK="hc";
	public static final String FULLMOVE_NUMBER="fn";	
	
	private List<ChessCell> cells;
	private HashMap<String, Object> status;
	private EvaluateStalemate stalemate=new EvaluateStalemate();
//	private List<SetupListener> setupListeners;
//	private Map<Integer, ChessCell> cellsMap;
	private Logger logger=Logger.getLogger(ChessBoard.class.getName());


	public ChessBoard() {
		super();
		cells=new ArrayList<ChessCell>();
//		setupListeners=new ArrayList<SetupListener>();
		status=new HashMap<String, Object>();
	//	cellsMap=new HashMap<Integer, ChessCell>();
		for(int r=0;r<ChessBoard.SIDE;r++){
			for(int c=0;c<ChessBoard.SIDE;c++){
				ChessCell cell=new ChessCell(r,c);
				cells.add(cell);
		//		cellsMap.put(cell.getAbsolutePosition(), cell);
			}
		}
		setTurn(WHITE);
	}
	
	public ChessBoard(ChessBoard ori) {
		super();
		cells=new ArrayList<ChessCell>();
		//		setupListeners=new ArrayList<SetupListener>();
		status=new HashMap<String, Object>();
		//	cellsMap=new HashMap<Integer, ChessCell>();
		List<ChessCell> cellsList=(List<ChessCell>)ori.getCells();
		for (ChessCell chessCell : cellsList) {
			ChessCell newCell=new ChessCell(chessCell);
			cells.add(newCell);
		}
		logger.debug("Clonando el tablero "+ori);
		Set<String> set=ori.getStatus().keySet();
		for (String	key : set) {
			getStatus().put(key, ori.getStatus().get(key));
		}
		logger.debug("Clon resultante:"+this);
	}
	
	public HashMap<String, Object> getStatus() {
		return status;
	}

	public void setStatus(HashMap<String, Object> status) {
		this.status = status;
	}
	
	/**
	 * Returns a String that represents the board. It assumes that the list of Cells are completly
	 */
	public String toString(){
		String line="-----------------------------------------\n";
		StringBuffer stringBuffer=new StringBuffer();
		Collections.sort(cells);
		stringBuffer.append(line);
		for (ChessCell cell : cells) {
			if(((ChessPosition)cell.getPosition()).getCol()==0){
				stringBuffer.append("|");				
			}
			if(cell.getPieces().isEmpty()){
				stringBuffer.append("    |");
			}else{
				stringBuffer.append(cell.getPieces().get(0).toString()+"|");
			}

			if(((ChessPosition)cell.getPosition()).getCol()==7){
				stringBuffer.append("\n");
				stringBuffer.append(line);				
			}			
		}
		return stringBuffer.toString();
	}

	@Override
	public List<? extends Cell> getCells() {
		return cells;
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean setup(List<? extends Cell> newCells) {
		if(newCells!=null){
			replaceCells((List<ChessCell>)newCells);
		}
		return true;
	}
		
	/**
	 * Actualiza las piezas contenidas en la lista de celdas
	 * @param newCells
	 * @return
	 */
	private List<ChessCell> replaceCells(List<ChessCell> newCells){
		logger.debug("Celdas Iniciales:"+newCells);
		for (ChessCell newCell : newCells) {
			ChessCell cell=cells.get(newCell.getAbsolutePosition());
			if(!cell.getPieces().isEmpty()){
				cell.clear();
			}	//El set cell automaticamente adiciona la pieza a la celda
//			if(!newCell.getPieces().isEmpty()){
				((ChessPiece)newCell.getPieces().get(0)).setCell(cell);
	//		}
				//cell.addPiece(newCell.getPieces().get(0));
		}
		return cells;
	}
		
	public Cell getCell(int row,int col){
		return cells.get(row*8+col);
	}

	public Cell getCell1(int row,int col){
		return cells.get((row-1)*8+(col-1));
	}

	public void setTurn(String turn){
		status.put(TURN, turn);
	}
	
	public String getTurn(){
		return (String)status.get(TURN);
	}
	
	public String getPreviousTurn(){
		if(getTurn().equals(BLACK)){
			return WHITE;
		}else{
			return BLACK;
		}	
	}
	
	public String changeTurn(){
		if(getTurn().equals(BLACK)){
			setTurn(WHITE);
		}else{
			setTurn(BLACK);
		}
		return getTurn();
	}
	
	/**
	 * Returns a String that represents the ChessBoard in a FEN modified format. The variation consist in that the
	 * order of processing ranks is from 1 to 8 (the opposite way of standard FEN).
	 * @return FEN modified format of the board
	 */
	public String getFEN(){
		String fen="";
		int spaces=0;
		int pos=0;
		for (ChessCell cell : cells) {
			if(cell.getPieces().isEmpty()){
				spaces++;
			}else{
				if(spaces>0){
					fen+=spaces;
					spaces=0;
				}
				ChessPiece piece=(ChessPiece)cell.getPieces().get(0);
				fen+=piece.getFEN();
			}
			pos++;
			if((pos%8)==0){
				if(spaces!=0){
					fen+=spaces;
				}
				fen+="/";
				spaces=0;
			}
		}
		fen=fen.substring(0,fen.length()-1);
		fen+=" "+getTurn().charAt(0);
		String castling="";
		if(status.get("w"+SHORT_CASTLING)==("y")){
			castling+="K";
		}
		if(status.get("w"+LONG_CASTLING)==("y")){
			castling+="Q";
		}
		if(status.get("b"+SHORT_CASTLING)==("y")){
			castling+="k";
		}
		if(status.get("b"+LONG_CASTLING)==("y")){
			castling+="q";
		}
		if(castling.equals("")){
			castling="-";
		}
		fen+=" "+castling;
		String pas=(String)status.get(ET_PASSANT);
		String pas2="";
		if(pas!=null){
			pas2+=(char)(Integer.parseInt(pas.substring(0,1))+ChessController.ASCII_a);
			pas2+=pas.substring(1,2);
		}else{
			pas2="-";
		}
		fen+=" "+pas2;
		// FIXME Completar la funcionalidad agregando el halfmove clock y el fullmove counter
		return fen;
	}
	
	public double getUtility(String player,IEvaluator evaluator){
		double eval=stalemate.evaluate(this, player);
		if(eval==0d){
			return evaluator.evaluate(this,player);
		}
		return eval;
	}
	
}
